package player_model

import (
	"math/rand"
	"strings"
	"time"

	"gddgame.cc/galaxy/common/dsl/game"
	. "gddgame.cc/galaxy/common/dsl/web"
	"gddgame.cc/galaxy/utils/orm"
)

type PlayerModelData struct {
	Models   []PlayerModel
	ModelMap map[string]*PlayerModel

	lastModelUpdateTime *time.Time

	modelModel     *orm.Model
	userModelModel *orm.Model
}

func GetPlayerModelData(env *game.Environment) (*PlayerModelData, error) {
	var err error
	data := &PlayerModelData{}
	if data.modelModel, data.Models, data.ModelMap, err = getModelData(env); err != nil {
		return nil, err
	}
	if data.userModelModel, err = env.GetModel(PlayerUserModelName); err != nil {
		return nil, err
	}

	for _, model := range data.Models {
		if data.lastModelUpdateTime == nil || model.UpdateTime.After(*data.lastModelUpdateTime) {
			data.lastModelUpdateTime = model.UpdateTime
		}
	}

	return data, nil
}
func getModelData(env *game.Environment) (*orm.Model, []PlayerModel, map[string]*PlayerModel, error) {
	var err error
	var models []PlayerModel

	model, err := env.GetModel(PlayerModelName)
	if err != nil {
		return nil, nil, nil, err
	}
	_, err = model.Query().Find(&models)
	if err != nil {
		return nil, nil, nil, err
	}
	modelMap := make(map[string]*PlayerModel, len(models))
	for k := range models {
		modelMap[models[k].Key] = &models[k]
	}
	return model, models, modelMap, nil
}
func (data *PlayerModelData) Random() *PlayerModel {
	l := len(data.Models)
	return &data.Models[rand.Int31n(int32(l))]
}

func (data *PlayerModelData) HasModel(userId int, modelKey string) bool {
	var uModel PlayerUserModel
	ok, _ := data.userModelModel.Query().Where("=", "user_id", userId).Where("=", "model_key", modelKey).One(&uModel)
	return ok
}

func (data *PlayerModelData) CanModel(modelKey string, gold int) bool {
	model := data.ModelMap[modelKey]
	return model.Gold < gold
}

func (data *PlayerModelData) AddModel(userId int, modelKey string, userData map[string]interface{}) error {
	if _, err := data.userModelModel.Insert(&PlayerUserModel{
		UserId:   userId,
		ModelKey: modelKey,
	}); err != nil {
		return SystemExceptionDetail("添加模型失败", err)
	}
	model := data.ModelMap[modelKey]
	if model.Gold > 0 {
		userData["gold"] = &orm.UpdateOperate{Operate: "-", Value: model.Gold}
	}
	return nil
}

func (data *PlayerModelData) GetAllModel(userId int, useModel string, updateTime *time.Time) ([]*PlayerModelExtend, error) {
	var err error
	var uModels []PlayerUserModel
	query := data.userModelModel.Query().Where("=", "user_id", userId)
	if updateTime != nil {
		ids := []string{}
		for key := range data.Models {
			model := &data.Models[key]
			if updateTime.Before(*model.UpdateTime) {
				ids = append(ids, model.Key)
			}
		}
		if len(ids) > 0 {
			query.WhereSql("(update_time > ? or model_key in ('"+strings.Join(ids, "','")+"'))", updateTime)
		} else {
			query.Where(">", "update_time", updateTime)
		}
	}
	if _, err = query.Find(&uModels); err != nil {
		return nil, SystemExceptionDetail("查找用户模型失败", err)
	}
	uModelMap := make(map[string]*PlayerUserModel, len(uModels))
	for k := range uModels {
		uModelMap[uModels[k].ModelKey] = &uModels[k]
	}
	// 获取道具信息
	models := make([]*PlayerModelExtend, 0, 10)
	for key := range data.Models {
		model := &data.Models[key]
		if u, ok := uModelMap[model.Key]; ok {
			if model.Key == useModel {
				u.Use = true
			}
			models = append(models, NewPlayerModelExtend(model, u))
		} else if updateTime == nil || updateTime.Before(*model.UpdateTime) {
			models = append(models, NewPlayerModelExtend(model, nil))
		}
	}
	return models, nil
}
